package za.org.jcicada.katcp;

/**
 * DeviceLogger.java
 *
 * @author Simon Cross
 *
 * Created on October 17, 2008, 17:16
 */

import za.org.jcicada.katcp.BaseServer;

/**
 * A logger helper for an instance of a katcp.BaseServer subclass.
 *
 * Log messages are logged at a particular level and under
 * a particular name. Names use dotted notation to form
 * a virtual hierarchy of loggers with the device.
 */
public class DeviceLogger {

    /**
     * Logging levels.
     */
    // Level enum ordinal values are used as to determine what should be logged
    // so this list should be kept in the right order. The names of the enums
    // are part of the protocol defined by KATCP and so these should also
    // only change if the protocol does.
    public enum Level {
        /** Receive logs at the most detailed level. */ ALL,
        /** Extremely verbose logging for detailed analysis. */ TRACE,
        /** Verbose logging for debugging. */ DEBUG,
        /** Information about workflow at course grained level. */ INFO,
        /** Log an abnormal condition. */ WARN,
        /** Log a device error. */ ERROR,
        /** Log a complete device failure. */ FATAL,
        /** Turn off logging. */ OFF;
    
        /**
         * Return the name of the level value.
         *
         * @return The KATCP name for this logging Level.
         */
        public String katcpName() {
            return name().toLowerCase();
        }

        /**
         * Find a level for the given KATCP name.
         *
         * @param name KATCP name of a logging Level.
         * @return Level for the given name.
         */
        public static Level fromKatcpName(String name) {
            Level level;
            try {
                level = Level.valueOf(Level.class, name.toUpperCase());
            }
            catch (IllegalArgumentException e) {
                throw new IllegalArgumentException(String.format("Unknown logging level name '%s'", name));
            }
            return level;
        }        
    };

    /**
     * The Server this DeviceLogger logs for.
     */
    protected final BaseServer server;

    /**
     * The current logging level.
     */
    protected Level logLevel = Level.OFF;

    /**
     * The root logger name.
     */
    protected String rootLoggerName = "root";

    /**
     * Construct a DeviceLogger.
     *
     * @param server  The server to log for.
     */
    public DeviceLogger(BaseServer server) {
        this.server = server;
    }

    /**
     * Construct a DeviceLogger.
     *
     * @param server  The server to log for.
     * @param root  The name for the root logger.
     */  
    public DeviceLogger(BaseServer server, String root) {
        this.server = server;
        this.rootLoggerName = root;
    }

    /**
     * Return the current logging level.
     *
     * @return The current logging level.
     * @see #setLogLevel
     */
    public Level getLogLevel() {
        return logLevel;
    }

    /**
     * Set the logging level.
     *
     * @param level  The logging level to set.
     * @see #getLogLevel
     */
    public void setLogLevel(Level level) {
        logLevel = level;
    }

    /**
     * Set the logging level using a level name.
     *
     * @param levelName  The name of the logging level to set.
     */
    public void setLogLevelByName(String levelName) {
        logLevel = Level.fromKatcpName(levelName);
    }
    
    /**
     * Log a message and inform all clients.
     *
     * @param level  The level to log at.
     * @param msg  The log message.
     * @param name  The name of the logger to log to (or null for the root logger).
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void log(Level level, String msg, String name)
    throws BaseServer.MessageSendException {
        if (level.compareTo(logLevel) >= 0) {
            if (name == null)
                name = rootLoggerName;
            server.informAll(server.logMessage(level.katcpName(), msg, name));
        }
    }

    /**
     * Log a trace message.
     *
     * @param msg  The log message.
     * @param name  The name of the logger to log to (or null for the root logger).
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void trace(String  msg, String name)
    throws BaseServer.MessageSendException {
        log(Level.TRACE, msg, name);
    }

    /**
     * Log a trace message on the default logger.
     *
     * @param msg  The log message.
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void trace(String  msg)
    throws BaseServer.MessageSendException {
        log(Level.TRACE, msg, null);
    }
    
    /**
     * Log a debug message.
     *
     * @param msg  The log message.
     * @param name  The name of the logger to log to (or null for the root logger).
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void debug(String msg, String name)
    throws BaseServer.MessageSendException {
        log(Level.DEBUG, msg, name);
    }

    /**
     * Log a debug message on the default logger.
     *
     * @param msg  The log message.
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void debug(String msg)
    throws BaseServer.MessageSendException {
        log(Level.DEBUG, msg, null);
    }

    /**
     * Log an info message.
     *
     * @param msg  The log message.
     * @param name  The name of the logger to log to (or null for the root logger).
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void info(String msg, String name)
    throws BaseServer.MessageSendException {
        log(Level.INFO, msg, name);
    }

    /**
     * Log an info message on the default logger.
     *
     * @param msg  The log message.
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void info(String msg)
    throws BaseServer.MessageSendException {
        log(Level.INFO, msg, null);
    }

    /**
     * Log an warning message.
     *
     * @param msg  The log message.
     * @param name  The name of the logger to log to (or null for the root logger).
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void warn(String msg, String name)
    throws BaseServer.MessageSendException {
        log(Level.WARN, msg, name);
    }

    /**
     * Log an warning message on the default logger.
     *
     * @param msg  The log message.
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void warn(String msg)
    throws BaseServer.MessageSendException {
        log(Level.WARN, msg, null);
    }

    /**
     * Log an error message.
     *
     * @param msg  The log message.
     * @param name  The name of the logger to log to (or null for the root logger).
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void error(String msg, String name)
    throws BaseServer.MessageSendException {
        log(Level.ERROR, msg, name);
    }

    /**
     * Log an error message on the default logger.
     *
     * @param msg  The log message.
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void error(String msg)
    throws BaseServer.MessageSendException {
        log(Level.ERROR, msg, null);
    }
    
    /**
     * Log a fatal error message.
     *
     * @param msg  The log message.
     * @param name  The name of the logger to log to (or null for the root logger).
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void fatal(String msg, String name)
    throws BaseServer.MessageSendException {
        log(Level.FATAL, msg, name);
    }

    /**
     * Log a fatal error message on the default logger.
     *
     * @param msg  The log message.
     * @throws BaseServer.MessageSendException  If sending the log message fails.
     */
    public void fatal(String msg)
    throws BaseServer.MessageSendException {
        log(Level.FATAL, msg, null);
    }
}
